// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef NET_HTTP_HTTP_STATUS_LINE_VALIDATOR_H_
#define NET_HTTP_HTTP_STATUS_LINE_VALIDATOR_H_

#include <stddef.h>

#include <vector>

#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "net/base/net_export.h"

namespace net {

class HttpStatusLineValidator {
public:
    // RFC 7230 S3.1.2:
    //   status-line = HTTP-version SP status-code SP reason-phrase CRLF
    //   status-code = 3DIGIT
    //   reason-phrase = *( HTAB / SP / VCHAR / obs-text )
    // And from RFC 7230 S2.6:
    //   HTTP-version = HTTP-name "/" DIGIT "." DIGIT
    //   HTTP-name = "\x48\x54\x54\x50" ; ie, "HTTP" in uppercase
    enum StatusLineStatus {
        // No violations found.
        STATUS_LINE_OK = 0,
        // ""
        STATUS_LINE_EMPTY = 1,
        // "xyzzy"
        STATUS_LINE_NOT_HTTP = 2,
        // "HtTp/1.1 ..."
        STATUS_LINE_HTTP_CASE_MISMATCH = 3,
        // "HTTP" or "HTTP/"
        STATUS_LINE_HTTP_NO_VERSION = 4,
        // "HTTP/abc" or "HTTP/1" or "HTTP/1."
        STATUS_LINE_INVALID_VERSION = 5,
        // "HTTP/1.234 ..."
        STATUS_LINE_MULTI_DIGIT_VERSION = 6,
        // "HTTP/3.0 ..."
        STATUS_LINE_UNKNOWN_VERSION = 7,
        // "HTTP/0.9 ..."
        STATUS_LINE_EXPLICIT_0_9 = 8,
        // "HTTP/1.1"
        STATUS_LINE_MISSING_STATUS_CODE = 9,
        // "HTTP/1.1 abc"
        STATUS_LINE_INVALID_STATUS_CODE = 10,
        // "HTTP/1.1 123a"
        STATUS_LINE_STATUS_CODE_TRAILING = 11,
        // "HTTP/1.1 404", note that "HTTP/1.1 404 " is a valid empty reason phrase
        STATUS_LINE_MISSING_REASON_PHRASE = 12,
        // "HTTP/1.1 200 \x01"
        STATUS_LINE_REASON_DISALLOWED_CHARACTER = 13,
        // "HTTP/1.1   200 OK"
        STATUS_LINE_EXCESS_WHITESPACE = 14,
        // "HTTP/1.1 600 OK"
        STATUS_LINE_RESERVED_STATUS_CODE = 15,

        STATUS_LINE_MAX
    };

    // Checks for violations of the RFC 7230 S3.1.2 status-line grammar, and
    // returns the first violation found, or STATUS_LINE_OK if the status line
    // looks conforming.
    static StatusLineStatus NET_EXPORT_PRIVATE ValidateStatusLine(
        const base::StringPiece& status_line);

private:
    static StatusLineStatus CheckHttpVersionSyntax(
        const base::StringPiece& version);
    static StatusLineStatus CheckStatusCodeSyntax(
        const base::StringPiece& status_code);
    // Checks |fields| against the reason-phrase syntax in RFC 7230 S3.1.2, ie:
    //   reason-phrase = *( HTAB / SP / VCHAR / obs-text )
    // Note that the HTTP stream parser ignores the reason-phrase entirely, so
    // this check is needlessly pedantic.
    static StatusLineStatus CheckReasonPhraseSyntax(
        const std::vector<base::StringPiece>& fields,
        size_t start_index);

    DISALLOW_IMPLICIT_CONSTRUCTORS(HttpStatusLineValidator);
};

} // namespace net

#endif // NET_HTTP_HTTP_STATUS_LINE_VALIDATOR_H_
